package com.mz.mattress.admin.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.hutool.system.UserInfo;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.JsonNode;
import com.mz.mattress.admin.api.req.MemberMerQueryReq;
import com.mz.mattress.admin.api.resp.MemberMerType;
import com.mz.mattress.admin.api.resp.MerchantVo;
import com.mz.mattress.admin.common.FailMessage;
import com.mz.mattress.admin.mapper.*;
import com.mz.mattress.admin.service.MemberMerService;
import com.mz.mattress.api.common.Constants;
import com.mz.mattress.api.redis.RedisKeys;
import com.mz.mattress.api.common.Result;
import com.mz.mattress.api.common.ServiceException;
import com.mz.mattress.api.entity.*;
import com.mz.mattress.api.jwt.JwtTokenUtil;
import com.mz.mattress.api.jwt.MerchantJwt;
import com.mz.mattress.api.req.BindMobileReq;
import com.mz.mattress.api.req.MobileLoginReq;
import com.mz.mattress.api.req.UpdatePasswordReq;
import com.mz.mattress.api.req.WxLoginReq;
import com.mz.mattress.api.resp.UserAuth;
import com.mz.mattress.api.util.*;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.List;

@Service
@Slf4j
public class MemberMerServiceImpl implements MemberMerService {

    @Autowired
    private MemberMerMapper memberMerMapper;

    @Autowired
    private MemberLoginLogMapper memberLoginLogMapper;

    @Autowired
    private MerchantMapper merchantMapper;

    @Autowired
    private SaleMapper saleMapper;

    @Autowired
    private InvestorMapper investorMapper;

    @Resource(name = "merchantWxMaService")
    private WxMaService merchantWxMaService;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private MemberBalanceRecordMapper memberBalanceRecordMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public Result<IPage<MemberMer>> listPage(MemberMerQueryReq req) {
        Page page = req.newPage();
        Page<MemberMer> list = memberMerMapper.listPage(page, req.getMobile(), req.getStatus(), req.getType(), req.getStartTime(), req.getEndTime());
        return Result.ok(list);
    }

    @Override
    public Result<UserAuth> wxLogin(WxLoginReq req) {

        String code = req.getCode();
        UserInfo userInfo = req.getUserInfo();
        Integer type = req.getType();
        if (code == null || userInfo == null || type == null) {
            return Result.fail(FailMessage.BAD_ARGUMENT);
        }

        String sessionKey = null;
        String openId = null;
        String unionId = null;
        try {
            WxMaJscode2SessionResult result = merchantWxMaService.getUserService().getSessionInfo(code);
            sessionKey = result.getSessionKey();
            openId = result.getOpenid();
            log.info("openId={}", openId);
            unionId = result.getUnionid();
        } catch (Exception e) {
            log.info("getSessionInfo_error", e);
        }

        if (sessionKey == null || openId == null) {
            log.error("invoke_weixin_fail,code={}", code);
            return Result.fail(FailMessage.WX_INVOKE_FAIL);
        }

        List<MemberMer> list = memberMerMapper.selectByOpenId(openId);
        if (list.size() > 1) {
            log.error("openId_error,openId={}", openId);
            return Result.fail(FailMessage.OPENID_ERROR);
        }

        MemberMer memberMer = new MemberMer();
        if (list.isEmpty()) {
            //注册新用户
            memberMer.setId(IdUtil.getMemberId());
            memberMer.setOpenId(openId);
            memberMer.setUnionId(unionId);
            memberMer.setSessionKey(sessionKey);
            memberMer.setAvatar(Constants.AVATAR);
            memberMer.setNickname("微信用户");
            //类型 按照注册请求类型
            memberMer.setType(type);
            memberMer.setTypeId(Constants.TYPE_ID_NOT_FIND);
            memberMer.setStatus(0);
            memberMer.setBalance(0);
            memberMer.setFreeze(0);
            memberMer.setSumIncome(0);
            memberMer.setSumCashOut(0);
            memberMerMapper.insert(memberMer);

        } else {
            //更新最后登录信息
            MemberMer mer = list.get(0);

            if (mer.getType() != null && mer.getTypeId() > 0 && mer.getType() != type) {
//                log.info("wxLogin_req_type={},now_type={},memberMerId={}", type, mer.getType(), mer.getId());
//                String roleName = "";
//                if (type == Constants.ROLE_MERCHANT) {
//                    roleName = "商家";
//                } else if (type == Constants.ROLE_SALE) {
//                    roleName = "服务商";
//                } else if (type == Constants.ROLE_INVESTOR) {
//                    roleName = "投资商";
//                }
//                return Result.fail("该用户角色和之前对不上,现请求是" + roleName);

                log.info("wxLogin_req_type={},now_type={},memberMerId={}", type, mer.getType(), mer.getId());

                //用现在请求的角色 登录
                MemberMerType merType = findTypeId(type, mer.getId(), mer.getMobile());
                memberMer.setName(merType.getName());
                memberMer.setType(merType.getType());
                memberMer.setTypeId(merType.getTypeId());
            }
            //刷新 typeId
            else if (mer.getTypeId() == null || mer.getTypeId() <= 0) {
                MemberMerType merType = findTypeId(type, mer.getId(), mer.getMobile());
                memberMer.setName(merType.getName());
                memberMer.setType(merType.getType());
                memberMer.setTypeId(merType.getTypeId());
            } else {
                memberMer.setTypeId(mer.getTypeId());
            }

            memberMer.setId(mer.getId());
            memberMer.setType(type);
            memberMer.setSessionKey(sessionKey);
            memberMer.setMobile(mer.getMobile());

            memberMerMapper.updateById(memberMer);
        }

        MerchantJwt merchantJwt = new MerchantJwt();
        merchantJwt.setOpenId(openId);
        merchantJwt.setMemberMerId(memberMer.getId());
        merchantJwt.setSessionKey(memberMer.getSessionKey());
        merchantJwt.setMobile(memberMer.getMobile());
        merchantJwt.setType(memberMer.getType());
        merchantJwt.setTypeId(memberMer.getTypeId());

        insertLoginLog(memberMer.getId(), req.getIp());

        String token = JwtTokenUtil.createMerchantToken(merchantJwt);
//        String inviteCode = InviteCodeUtils.idToCode(memberMer.getId());
//        token, memberMer.getMobile(), memberMer.getType(), memberMer.getTypeId()

        UserAuth userAuth = new UserAuth();
        userAuth.setToken(token);
        userAuth.setMobile(memberMer.getMobile());

        //销售 和 子销售 都转成销售
        if (memberMer.getType() == 2 || memberMer.getType() == 3) {
            userAuth.setType(2);
        } else {
            userAuth.setType(memberMer.getType());
        }

        userAuth.setTypeId(memberMer.getTypeId());

        return Result.ok(userAuth);
    }

    @Override
    public Result<UserAuth> mobileLogin(MobileLoginReq req) {

        String mobile = req.getMobile();
        MemberMer memberMer = memberMerMapper.selectByMobile(mobile);
        if (memberMer == null) {
            return Result.fail("找不到用户");
        }
        if (StringTools.isEmpty(memberMer.getPassword())) {
            return Result.fail("未设密码");
        }

        if (!passwordEncoder.matches(req.getPassword(), memberMer.getPassword())) {
            return Result.fail("密码错误");
        }

        insertLoginLog(memberMer.getId(), req.getIp());

        UserAuth userAuth = new UserAuth();
        userAuth.setMobile(mobile);
        userAuth.setToken(resetToken(mobile, memberMer));
        //销售 和 子销售 都转成销售
        if (memberMer.getType() == 2 || memberMer.getType() == 3) {
            userAuth.setType(2);
        } else {
            userAuth.setType(memberMer.getType());
        }
        userAuth.setTypeId(memberMer.getTypeId());

        return Result.ok(userAuth);
    }

    /**
     * 查找类型Id  typeId
     * @param type     1商户 2销售 3子销售 4投资商
     * @param memberId
     * @param mobile
     * @return
     */
//    public Pair<Integer, Integer> findTypeId(Integer type, Long memberId, String mobile) {
//
//        if (type == Constants.ROLE_MERCHANT) {
//            // 会有多家门店
//            MerchantVo one = merchantMapper.selectOne(memberId);
//            if (one != null) {
//                Pair<Integer, Integer> pair = new Pair<>(type, one.getId());
//                return pair;
//            }
//
//        } else if (type == Constants.ROLE_SALE && mobile != null) {
//
//            Sale sale = saleMapper.selectByMobile(mobile);
//            if (sale == null) {
//                log.info("find_no_sale_by_mobile=" + mobile);
//                throw new ServiceException("找不到服务商信息");
//            }
//
//            //销售绑定会员ID
//            if (sale.getMemberId() == null) {
//                Sale update = new Sale();
//                update.setId(sale.getId());
//                update.setMemberId(memberId);
//                saleMapper.updateById(update);
//            }
//
//            if (sale.getPid() == 0) {
//                return new Pair<>(2, sale.getId());
//            }
//
//            return new Pair<>(3, sale.getId());
//
//        } else if (type == Constants.ROLE_INVESTOR && mobile != null) {
//
//            Investor investor = investorMapper.selectByMobile(mobile);
//            if (investor == null) {
//                log.info("find_no_investor_by_mobile=" + mobile);
//                throw new ServiceException("找不到投资商信息");
//            }
//
//            //销售绑定会员ID
//            if (investor.getMemberId() == null) {
//                Investor update = new Investor();
//                update.setId(investor.getId());
//                update.setMemberId(memberId);
//                investorMapper.updateById(update);
//            }
//
//            return new Pair<>(4, investor.getId());
//        }
//
//        //没找到 返回-1
//        return new Pair<>(type, Constants.TYPE_ID_NOT_FIND);
////        return Constants.TYPE_ID_NOT_FIND;
//    }

    /**
     * 查找类型Id  typeId
     * @param type     1商户 2销售 3子销售 4投资商
     * @param memberId
     * @param mobile
     * @return
     */
    public MemberMerType findTypeId(Integer type, Long memberId, String mobile) {

        if (type == Constants.ROLE_MERCHANT) {
            // 会有多家门店  找不禁用的商家
            MerchantVo one = merchantMapper.selectOne(memberId);
            if (one != null) {
                MemberMerType merType = new MemberMerType();
                merType.setName(one.getName());
                merType.setTypeId(type);
                merType.setTypeId(one.getId());
                return merType;
            }

        } else if (type == Constants.ROLE_SALE && mobile != null) {

            Sale sale = saleMapper.selectByMobile(mobile);
            if (sale == null) {
                log.info("find_no_sale_by_mobile=" + mobile);
                throw new ServiceException("找不到服务商信息");
            }

            //销售绑定会员ID
            if (sale.getMemberId() == null) {
                Sale update = new Sale();
                update.setId(sale.getId());
                update.setMemberId(memberId);
                saleMapper.updateById(update);
            }

            if (sale.getPid() == 0) {

                MemberMerType merType = new MemberMerType();
                merType.setName(sale.getName());
                merType.setType(2);
                merType.setTypeId(sale.getId());
                return merType;
            }

            MemberMerType merType = new MemberMerType();
            merType.setName(sale.getName());
            merType.setType(3);
            merType.setTypeId(sale.getId());
            return merType;

        } else if (type == Constants.ROLE_INVESTOR && mobile != null) {

            Investor investor = investorMapper.selectByMobile(mobile);
            if (investor == null) {
                log.info("find_no_investor_by_mobile=" + mobile);
                throw new ServiceException("找不到投资商信息");
            }

            //销售绑定会员ID
            if (investor.getMemberId() == null) {
                Investor update = new Investor();
                update.setId(investor.getId());
                update.setMemberId(memberId);
                investorMapper.updateById(update);
            }

            MemberMerType merType = new MemberMerType();
            merType.setName(investor.getName());
            merType.setType(4);
            merType.setTypeId(investor.getId());
            return merType;
        }

        MemberMerType merType = new MemberMerType();
        merType.setType(type);
        merType.setTypeId(Constants.TYPE_ID_NOT_FIND);
        return merType;

        //没找到 返回-1
//        return new Pair<>(type, Constants.TYPE_ID_NOT_FIND);
//        return Constants.TYPE_ID_NOT_FIND;
    }

    @Override
    public Result<UserAuth> bindWxMobile(String sessionkey, String data, Long memberId) {

        String mobile = null;
        try {
            //{"errMsg":"getPhoneNumber:fail:user cancel"}
            if (data == null) {
                log.info("data=null,bindWxMobile");
                return Result.fail();
            }
            JsonNode jsonNode = JacksonUtils.toObj(data);
            if (jsonNode.get("encryptedData") == null || jsonNode.get("iv") == null) {
                return Result.fail();
            }

            String encryptedData = jsonNode.get("encryptedData").textValue();
//            type = jsonNode.get("type").textValue();
            String iv = jsonNode.get("iv").textValue();

            log.info("encryptedData={},iv={}", encryptedData, iv);

            //获取用户绑定微信的手机号
            WxMaPhoneNumberInfo phoneNumberInfo = merchantWxMaService.getUserService().getPhoneNoInfo(sessionkey, encryptedData, iv);
            mobile = phoneNumberInfo.getPhoneNumber();
        } catch (Exception e) {
            log.error("bindMobile_wx_fail,data=" + data);
            log.error("bindMobile_wx_fail", e);
            return Result.fail();
        }

        return doBindMobile(mobile, memberId);
    }

//    @Override
//    public Result<String> switchMerchantCreateToken(String mobile, Integer merchantId, Long memberId) {
//
//        MemberMer memberMer = memberMerMapper.selectById(memberId);
//        if (memberMer == null) {
//            return Result.fail("用户不存在");
//        }
//
//        if (memberMer.getType() == 1) {
//            return Result.fail("该用户不是商家");
//        }
//
//        MemberMer update = new MemberMer();
//        update.setId(memberId);
//        update.setType(1);
//        update.setTypeId(merchantId);
//        memberMerMapper.updateById(update);
//
//        memberMer.setTypeId(merchantId);
//
//        String token = resetToken(mobile, memberMer);
//        return Result.ok(token);
//    }

    @Override
    public Result<UserAuth> bindMobile(BindMobileReq req, Long memberId) {

        String mobile = req.getMobile();
        String code = req.getCode();

        log.info("bindMobile_req,mobile={},code={}", mobile, code);
        if (StringUtils.isEmpty(mobile)
                || StringUtils.isEmpty(code)) {
            return Result.fail(FailMessage.BAD_ARGUMENT);
        }

        // 检查手机号是否真实
        if (!RegexUtil.isMobileExact(mobile)) {
            log.error("bindMobile_mobile_fail,mobile={}", mobile);
            return Result.fail(FailMessage.INVALID_MOBILE);
        }

        Object object = redisTemplate.opsForValue().get(RedisKeys.getSmsMobileKey(mobile));
        if (object == null) {
            return Result.fail(FailMessage.BAD_ARGUMENT);
        }
        // 检查短信验证码是否正确
        if (!object.toString().equals(code)) {
            return Result.fail(FailMessage.WRONG_CODE_ARGUMENT);
        }

        return doBindMobile(mobile, memberId);
    }

    @Override
    public Result<MemberMer> getById(Long id) {
        MemberMer memberMer = memberMerMapper.selectById(id);
        return Result.ok(memberMer);
    }

    @Override
    public Result deleteById(Long id) {

        MemberMer memberMer = memberMerMapper.selectById(id);
        if (memberMer != null) {
            String mobile = memberMer.getMobile();
            merchantMapper.deleteByMobile(mobile);
            saleMapper.deleteByMobile(mobile);
        }

        memberMerMapper.deleteByMemberId(id);

        return Result.ok();
    }

    private Result<UserAuth> doBindMobile(String mobile, Long memberId) {

        // 检查手机号是否已注册
        MemberMer memberMer = memberMerMapper.selectByMobile(mobile);
        if (memberMer != null) {
            log.error("mobile_find_memberMer,mobile={}", mobile);
            return Result.fail("手机号已注册");
        }

        memberMer = memberMerMapper.selectById(memberId);
        if (memberMer == null) {
            return Result.fail("用户不存在");
        }

        MemberMer update = new MemberMer();
        update.setId(memberId);
        update.setMobile(mobile);
        memberMerMapper.updateById(update);

        if (memberMer.getTypeId() == null) {

//            Pair<Integer, Integer> pair = findTypeId(memberMer.getType(), memberId, mobile);
            MemberMerType merType = findTypeId(memberMer.getType(), memberId, mobile);

            memberMer.setName(merType.getName());
            memberMer.setType(merType.getType());
            memberMer.setTypeId(merType.getTypeId());
        }

        UserAuth userAuth = new UserAuth();
        userAuth.setMobile(mobile);
        userAuth.setToken(resetToken(mobile, memberMer));
        //销售 和 子销售 都转成销售
        if (memberMer.getType() == 2 || memberMer.getType() == 3) {
            userAuth.setType(2);
        } else {
            userAuth.setType(memberMer.getType());
        }
        userAuth.setTypeId(memberMer.getTypeId());

        return Result.ok(userAuth);

    }

    @Override
    public Result cashOut(Long memberId, String cashId, Integer money) {

        if (money <= 0) {
            return Result.fail("提现金额必须大于0");
        }

        MemberBalanceRecord record = memberBalanceRecordMapper.selectByCashId(cashId);
        if (record != null) {
            log.error("has_record,cashId=" + cashId);
            return Result.fail("已有提现记录");
        }

        log.info("cashOut_money,memberId={},money={},cashId={}", memberId, money, cashId);

        MemberMer memberMer = memberMerMapper.selectById(memberId);
        if (memberMer == null) {
            log.error("not_find_member,memberId=" + memberId);
            return Result.fail("找不到用户");
        }

        Integer count = memberMerMapper.freezeEffect(memberId, money, memberMer.getVersion());
        if (count <= 0) {
            log.error("not_freeze_use,memberId=" + memberId);
            return Result.fail("请稍后再试");
        }

//        Integer balance = memberMerMapper.lockMember(memberId);
//        if (balance == null) {
//            log.error("not_find_member,memberId=" + memberId);
//            return Result.fail("找不到用户");
//        }

//        memberMerMapper.subtractBalance(memberId, money);

        record = new MemberBalanceRecord();
        record.setMemberId(memberId);
        record.setBalance(memberMer.getBalance());
        record.setChanges(-money);
        record.setAfters(memberMer.getBalance() - money);
        record.setCashId(cashId);
        record.setRemark("提现");
        memberBalanceRecordMapper.insert(record);

        return Result.ok();
    }

    @Override
    public Result resetType(Long memberId) {
        memberMerMapper.resetType(memberId);
        return Result.ok();
    }

    @Override
    public Result resetPassword(Long memberId) {
        MemberMer member = new MemberMer();

        // 默认密码
        String newPwd = passwordEncoder.encode(Constants.DEFAULT_PWD);
        member.setPassword(newPwd);
        member.setId(memberId);
        memberMerMapper.updateById(member);

        return Result.ok();
    }

    @Override
    public Result updatePassword(UpdatePasswordReq req) {

        if (StringUtils.isEmpty(req.getNewPwd())) {
            return Result.fail("密码不能为空");
        }

        String oldPwd = req.getOldPwd();
        String newPwd = req.getNewPwd();

        String encodeNewPwd = passwordEncoder.encode(newPwd);

//        UserJwtClient userJwt = Holder.USER_JWT_WX_THREAD_LOCAL.get();
//        Long memberId = userJwt.getMemberId();
        MemberMer member = memberMerMapper.selectById(req.getMemberId());

        if (member.getPassword() != null) {

            //可以改密码

            if (StringTools.isEmpty(oldPwd)) {
                return Result.fail("请输入原密码");
            }

            if (!passwordEncoder.matches(oldPwd, member.getPassword())) {
                return Result.fail("旧密码错误");
            }
            if (passwordEncoder.matches(oldPwd, encodeNewPwd)) {
                return Result.fail("新密码不能与旧密码相同");
            }

        }

        MemberMer update = new MemberMer();
        update.setId(req.getMemberId());
        update.setPassword(encodeNewPwd);
        memberMerMapper.updateById(update);

        return Result.ok();

    }

    private String resetToken(String mobile, MemberMer memberMer) {

//        MerchantJwt merchantJwt = Holder.MERCHANT_JWT_THREAD_LOCAL.get();

        MerchantJwt merchantJwt = new MerchantJwt();
        merchantJwt.setOpenId(memberMer.getOpenId());
        merchantJwt.setMemberMerId(memberMer.getId());
        merchantJwt.setSessionKey(memberMer.getSessionKey());
        merchantJwt.setMobile(mobile);

//        MemberType memberType = findInfoByMobile(mobile);

        log.info("mobile={},type={},typeId={}", mobile, memberMer.getType(), memberMer.getTypeId());

        merchantJwt.setType(memberMer.getType());
        merchantJwt.setTypeId(memberMer.getTypeId());

        return JwtTokenUtil.createMerchantToken(merchantJwt);
    }

    private void insertLoginLog(Long memberId, String ip) {
        MemberLoginLog loginLog = new MemberLoginLog();
        loginLog.setMemberId(memberId);
        loginLog.setIp(ip);
        loginLog.setClient(2);
        memberLoginLogMapper.insert(loginLog);
    }

    @Data
    private class MemberType {

        //类型 1商家 2销售
        private Integer type;

        //类型对应商家销售ID
        private Integer typeId;

        //是否多家店
        private Integer multiShop;

    }

}
